package ongd.servicios.persistencia;

import java.io.Serializable;
import javax.persistence.EntityManager;
import javax.persistence.EntityNotFoundException;
import ongd.negocio.gestion.Persona;
import java.util.ArrayList;
import java.util.List;
import ongd.negocio.gestion.Proyecto;
import ongd.negocio.gestion.Subvencion;
import ongd.negocio.gestion.Apadrinado;
import ongd.negocio.gestion.Entidad;
import ongd.negocio.gestion.PersonaContacto;
import ongd.servicios.persistencia.exceptions.IllegalOrphanException;
import ongd.servicios.persistencia.exceptions.NonexistentEntityException;
import ongd.servicios.persistencia.exceptions.PreexistingEntityException;

/**
 * Clase que contiene los método que para realizar operaciones
 * sobre la base de datos referente a la entidad proyecto.
 *
 * @author <a href="mailto:egi0002@alu.ubu.es">Elena García Iglesias</a>
 * @author <a href="mailto:cms0021@alu.ubu.es">Cristina Martínez Sanz</a>
 * @version 1.0 20120124
 *
 */
public class ProyectoJpaController extends AJPAControlador implements Serializable {

    /**
     * Objeto de tipo EntityManager.
     */
    private EntityManager em = null;

    /**
     * Constructor de la clase.
     * @param em EntityManager
     */
    public ProyectoJpaController(EntityManager em) {
        this.em = em;
    }

    /**
     * Método que crea un objeto de tipo proyecto en la base de datos.
     * @param entidad Objeto que crearemos 
     * @param et Booleano que indica si hay que iniciar la transacción
     * @throws PreexistingEntityException
     * @throws Exception 
     */
    @Override
    public void create(Entidad entidad, boolean et) throws PreexistingEntityException, Exception {
        Proyecto proyecto = (Proyecto) entidad;
        if (proyecto.getPersonaList() == null) {
            proyecto.setPersonaList(new ArrayList<Persona>());
        }
        if (proyecto.getSubvencionList() == null) {
            proyecto.setSubvencionList(new ArrayList<Subvencion>());
        }
        if (proyecto.getApadrinadoList() == null) {
            proyecto.setApadrinadoList(new ArrayList<Apadrinado>());
        }
        if (proyecto.getPersonaContactoList() == null) {
            proyecto.setPersonaContactoList(new ArrayList<PersonaContacto>());
        }
        try {
            //Si et es falso significa que tengo que crear la transacción
            if (!et) {
                em.getTransaction().begin();
            }
            if (proyecto.esProyectoApadrinamientoGeneral() || proyecto.esProyectoApadrinamientoPersonal()) {
                List<Persona> attachedPersonaList = new ArrayList<Persona>();
                for (Persona personaListPersonaToAttach : proyecto.getPersonaList()) {
                    personaListPersonaToAttach = em.getReference(personaListPersonaToAttach.getClass(), personaListPersonaToAttach.getDni());
                    attachedPersonaList.add(personaListPersonaToAttach);
                }
                proyecto.setPersonaList(attachedPersonaList);
            }
            if (proyecto.esProyectoCooperacion() || proyecto.esProyectoSensibilizacion()) {
                List<Subvencion> attachedSubvencionList = new ArrayList<Subvencion>();
                for (Subvencion subvencionListSubvencionToAttach : proyecto.getSubvencionList()) {
                    subvencionListSubvencionToAttach = em.getReference(subvencionListSubvencionToAttach.getClass(), subvencionListSubvencionToAttach.getSubvencionPK());
                    attachedSubvencionList.add(subvencionListSubvencionToAttach);
                }
                proyecto.setSubvencionList(attachedSubvencionList);
            }
            if (proyecto.esProyectoApadrinamientoPersonal()) {
                List<Apadrinado> attachedApadrinadoList = new ArrayList<Apadrinado>();
                for (Apadrinado apadrinadoListApadrinadoToAttach : proyecto.getApadrinadoList()) {
                    apadrinadoListApadrinadoToAttach = em.getReference(apadrinadoListApadrinadoToAttach.getClass(), apadrinadoListApadrinadoToAttach.getApadrinadoPK());
                    attachedApadrinadoList.add(apadrinadoListApadrinadoToAttach);
                }
                proyecto.setApadrinadoList(attachedApadrinadoList);
            }
            List<PersonaContacto> attachedPersonaContactoList = new ArrayList<PersonaContacto>();
            for (PersonaContacto personaContactoListPersonaContactoToAttach : proyecto.getPersonaContactoList()) {
                personaContactoListPersonaContactoToAttach = em.getReference(personaContactoListPersonaContactoToAttach.getClass(), personaContactoListPersonaContactoToAttach.getPersonaContactoPK());
                attachedPersonaContactoList.add(personaContactoListPersonaContactoToAttach);
            }
            proyecto.setPersonaContactoList(attachedPersonaContactoList);
            em.persist(proyecto);
            if (proyecto.esProyectoApadrinamientoGeneral() || proyecto.esProyectoApadrinamientoPersonal()) {
                for (Persona personaListPersona : proyecto.getPersonaList()) {
                    personaListPersona.getProyectoList().add(proyecto);
                    personaListPersona = em.merge(personaListPersona);
                }
            }
            if (proyecto.esProyectoCooperacion() || proyecto.esProyectoSensibilizacion()) {
                for (Subvencion subvencionListSubvencion : proyecto.getSubvencionList()) {
                    Proyecto oldProyectoOfSubvencionListSubvencion = subvencionListSubvencion.getProyecto();
                    subvencionListSubvencion.setProyecto(proyecto);
                    subvencionListSubvencion = em.merge(subvencionListSubvencion);
                    if (oldProyectoOfSubvencionListSubvencion != null) {
                        oldProyectoOfSubvencionListSubvencion.getSubvencionList().remove(subvencionListSubvencion);
                        oldProyectoOfSubvencionListSubvencion = em.merge(oldProyectoOfSubvencionListSubvencion);
                    }
                }
            }
            if (proyecto.esProyectoApadrinamientoPersonal()) {
                for (Apadrinado apadrinadoListApadrinado : proyecto.getApadrinadoList()) {
                    Proyecto oldProyectoOfApadrinadoListApadrinado = apadrinadoListApadrinado.getProyecto();
                    apadrinadoListApadrinado.setProyecto(proyecto);
                    apadrinadoListApadrinado = em.merge(apadrinadoListApadrinado);
                    if (oldProyectoOfApadrinadoListApadrinado != null) {
                        oldProyectoOfApadrinadoListApadrinado.getApadrinadoList().remove(apadrinadoListApadrinado);
                        oldProyectoOfApadrinadoListApadrinado = em.merge(oldProyectoOfApadrinadoListApadrinado);
                    }
                }
            }
            for (PersonaContacto personaContactoListPersonaContacto : proyecto.getPersonaContactoList()) {
                Proyecto oldProyectoOfPersonaContactoListPersonaContacto = personaContactoListPersonaContacto.getProyecto();
                personaContactoListPersonaContacto.setProyecto(proyecto);
                personaContactoListPersonaContacto = em.merge(personaContactoListPersonaContacto);
                if (oldProyectoOfPersonaContactoListPersonaContacto != null) {
                    oldProyectoOfPersonaContactoListPersonaContacto.getPersonaContactoList().remove(personaContactoListPersonaContacto);
                    oldProyectoOfPersonaContactoListPersonaContacto = em.merge(oldProyectoOfPersonaContactoListPersonaContacto);
                }
            }
            //Si et es falso significa que tengo que terminar la transaccion
            if (!et) {
                em.getTransaction().commit();
            }
        } catch (Exception ex) {
            if (findEntidad(Proyecto.class, proyecto.getIdProyecto()) != null) {
                throw new PreexistingEntityException("Proyecto " + proyecto + " already exists.", ex);
            }
            throw ex;
        } finally {
            if (em != null) {
//                em.close();
            }
        }
    }

    /**
     * Método que edita un objeto de tipo proyecto en la base de datos.
     * @param entidad Entidad que editaremos
     * @param et Booleano que indica si hay que iniciar la transacción
     * @throws NonexistentEntityException
     * @throws Exception 
     * @throws IllegalOrphanException
     */
    @Override
    public void edit(Entidad entidad, boolean et) throws IllegalOrphanException, NonexistentEntityException, Exception {
        Proyecto proyecto = (Proyecto) entidad;
        try {
            //Si et es falso significa que tengo que crear la transacción
            if (!et) {
                em.getTransaction().begin();
            }
            Proyecto persistentProyecto = em.find(Proyecto.class, proyecto.getIdProyecto());
            List<Persona> personaListOld = persistentProyecto.getPersonaList();
            List<Persona> personaListNew = proyecto.getPersonaList();
            List<Subvencion> subvencionListOld = persistentProyecto.getSubvencionList();
            List<Subvencion> subvencionListNew = proyecto.getSubvencionList();
            List<Apadrinado> apadrinadoListOld = persistentProyecto.getApadrinadoList();
            List<Apadrinado> apadrinadoListNew = proyecto.getApadrinadoList();
            List<PersonaContacto> personaContactoListOld = persistentProyecto.getPersonaContactoList();
            List<PersonaContacto> personaContactoListNew = proyecto.getPersonaContactoList();
            List<String> illegalOrphanMessages = null;
            for (Subvencion subvencionListOldSubvencion : subvencionListOld) {
                if (!subvencionListNew.contains(subvencionListOldSubvencion)) {
                    if (illegalOrphanMessages == null) {
                        illegalOrphanMessages = new ArrayList<String>();
                    }
                    illegalOrphanMessages.add("You must retain Subvencion " + subvencionListOldSubvencion + " since its proyecto field is not nullable.");
                }
            }
            for (Apadrinado apadrinadoListOldApadrinado : apadrinadoListOld) {
                if (!apadrinadoListNew.contains(apadrinadoListOldApadrinado)) {
                    if (illegalOrphanMessages == null) {
                        illegalOrphanMessages = new ArrayList<String>();
                    }
                    illegalOrphanMessages.add("You must retain Apadrinado " + apadrinadoListOldApadrinado + " since its proyecto field is not nullable.");
                }
            }
            for (PersonaContacto personaContactoListOldPersonaContacto : personaContactoListOld) {
                if (!personaContactoListNew.contains(personaContactoListOldPersonaContacto)) {
                    if (illegalOrphanMessages == null) {
                        illegalOrphanMessages = new ArrayList<String>();
                    }
                    illegalOrphanMessages.add("You must retain PersonaContacto " + personaContactoListOldPersonaContacto + " since its proyecto field is not nullable.");
                }
            }
            if (illegalOrphanMessages != null) {
                throw new IllegalOrphanException(illegalOrphanMessages);
            }
            List<Persona> attachedPersonaListNew = new ArrayList<Persona>();
            for (Persona personaListNewPersonaToAttach : personaListNew) {
                personaListNewPersonaToAttach = em.getReference(personaListNewPersonaToAttach.getClass(), personaListNewPersonaToAttach.getDni());
                attachedPersonaListNew.add(personaListNewPersonaToAttach);
            }
            personaListNew = attachedPersonaListNew;
            proyecto.setPersonaList(personaListNew);
            List<Subvencion> attachedSubvencionListNew = new ArrayList<Subvencion>();
            for (Subvencion subvencionListNewSubvencionToAttach : subvencionListNew) {
                subvencionListNewSubvencionToAttach = em.getReference(subvencionListNewSubvencionToAttach.getClass(), subvencionListNewSubvencionToAttach.getSubvencionPK());
                attachedSubvencionListNew.add(subvencionListNewSubvencionToAttach);
            }
            subvencionListNew = attachedSubvencionListNew;
            proyecto.setSubvencionList(subvencionListNew);
            List<Apadrinado> attachedApadrinadoListNew = new ArrayList<Apadrinado>();
            for (Apadrinado apadrinadoListNewApadrinadoToAttach : apadrinadoListNew) {
                apadrinadoListNewApadrinadoToAttach = em.getReference(apadrinadoListNewApadrinadoToAttach.getClass(), apadrinadoListNewApadrinadoToAttach.getApadrinadoPK());
                attachedApadrinadoListNew.add(apadrinadoListNewApadrinadoToAttach);
            }
            apadrinadoListNew = attachedApadrinadoListNew;
            proyecto.setApadrinadoList(apadrinadoListNew);
            List<PersonaContacto> attachedPersonaContactoListNew = new ArrayList<PersonaContacto>();
            for (PersonaContacto personaContactoListNewPersonaContactoToAttach : personaContactoListNew) {
                personaContactoListNewPersonaContactoToAttach = em.getReference(personaContactoListNewPersonaContactoToAttach.getClass(), personaContactoListNewPersonaContactoToAttach.getPersonaContactoPK());
                attachedPersonaContactoListNew.add(personaContactoListNewPersonaContactoToAttach);
            }
            personaContactoListNew = attachedPersonaContactoListNew;
            proyecto.setPersonaContactoList(personaContactoListNew);
            proyecto = em.merge(proyecto);
            for (Persona personaListOldPersona : personaListOld) {
                if (!personaListNew.contains(personaListOldPersona)) {
                    personaListOldPersona.getProyectoList().remove(proyecto);
                    personaListOldPersona = em.merge(personaListOldPersona);
                }
            }
            for (Persona personaListNewPersona : personaListNew) {
                if (!personaListOld.contains(personaListNewPersona)) {
                    personaListNewPersona.getProyectoList().add(proyecto);
                    personaListNewPersona = em.merge(personaListNewPersona);
                }
            }
            for (Subvencion subvencionListNewSubvencion : subvencionListNew) {
                if (!subvencionListOld.contains(subvencionListNewSubvencion)) {
                    Proyecto oldProyectoOfSubvencionListNewSubvencion = subvencionListNewSubvencion.getProyecto();
                    subvencionListNewSubvencion.setProyecto(proyecto);
                    subvencionListNewSubvencion = em.merge(subvencionListNewSubvencion);
                    if (oldProyectoOfSubvencionListNewSubvencion != null && !oldProyectoOfSubvencionListNewSubvencion.equals(proyecto)) {
                        oldProyectoOfSubvencionListNewSubvencion.getSubvencionList().remove(subvencionListNewSubvencion);
                        oldProyectoOfSubvencionListNewSubvencion = em.merge(oldProyectoOfSubvencionListNewSubvencion);
                    }
                }
            }
            for (Apadrinado apadrinadoListNewApadrinado : apadrinadoListNew) {
                if (!apadrinadoListOld.contains(apadrinadoListNewApadrinado)) {
                    Proyecto oldProyectoOfApadrinadoListNewApadrinado = apadrinadoListNewApadrinado.getProyecto();
                    apadrinadoListNewApadrinado.setProyecto(proyecto);
                    apadrinadoListNewApadrinado = em.merge(apadrinadoListNewApadrinado);
                    if (oldProyectoOfApadrinadoListNewApadrinado != null && !oldProyectoOfApadrinadoListNewApadrinado.equals(proyecto)) {
                        oldProyectoOfApadrinadoListNewApadrinado.getApadrinadoList().remove(apadrinadoListNewApadrinado);
                        oldProyectoOfApadrinadoListNewApadrinado = em.merge(oldProyectoOfApadrinadoListNewApadrinado);
                    }
                }
            }
            for (PersonaContacto personaContactoListNewPersonaContacto : personaContactoListNew) {
                if (!personaContactoListOld.contains(personaContactoListNewPersonaContacto)) {
                    Proyecto oldProyectoOfPersonaContactoListNewPersonaContacto = personaContactoListNewPersonaContacto.getProyecto();
                    personaContactoListNewPersonaContacto.setProyecto(proyecto);
                    personaContactoListNewPersonaContacto = em.merge(personaContactoListNewPersonaContacto);
                    if (oldProyectoOfPersonaContactoListNewPersonaContacto != null && !oldProyectoOfPersonaContactoListNewPersonaContacto.equals(proyecto)) {
                        oldProyectoOfPersonaContactoListNewPersonaContacto.getPersonaContactoList().remove(personaContactoListNewPersonaContacto);
                        oldProyectoOfPersonaContactoListNewPersonaContacto = em.merge(oldProyectoOfPersonaContactoListNewPersonaContacto);
                    }
                }
            }
            //Si et es falso significa que tengo que terminar la transaccion
            if (!et) {
                em.getTransaction().commit();
            }
        } catch (Exception ex) {
            String msg = ex.getLocalizedMessage();
            if (msg == null || msg.length() == 0) {
                Integer id = proyecto.getIdProyecto();
                if (findEntidad(Proyecto.class, id) == null) {
                    throw new NonexistentEntityException("The proyecto with id " + id + " no longer exists.");
                }
            }
            throw ex;
        } finally {
            if (em != null) {
//                em.close();
            }
        }
    }

    /**
     * Método que borra un objeto de tipo proyecto de la base de datos.
     * @param clase Clase correpondiente al objeto a borrar
     * @param id Clave primaria del objeto a borrar
     * @param et Booleano que indica si hay que iniciar la transaccion
     * @throws NonexistentEntityException 
     * @throws IllegalOrphanException
     */
    @Override
    public void destroy(Class clase, Object id, boolean et) throws IllegalOrphanException, NonexistentEntityException {
        try {
            //Si et es falso significa que tengo que crear la transacción
            if (!et) {
                em.getTransaction().begin();
            }
            Proyecto proyecto;
            try {
                proyecto = (Proyecto) em.getReference(clase, id);
                proyecto.getIdProyecto();
            } catch (EntityNotFoundException enfe) {
                throw new NonexistentEntityException("The proyecto with id " + id + " no longer exists.", enfe);
            }
            List<String> illegalOrphanMessages = null;
            List<Subvencion> subvencionListOrphanCheck = proyecto.getSubvencionList();
            for (Subvencion subvencionListOrphanCheckSubvencion : subvencionListOrphanCheck) {
                if (illegalOrphanMessages == null) {
                    illegalOrphanMessages = new ArrayList<String>();
                }
                illegalOrphanMessages.add("This Proyecto (" + proyecto + ") cannot be destroyed since the Subvencion " + subvencionListOrphanCheckSubvencion + " in its subvencionList field has a non-nullable proyecto field.");
            }
            List<Apadrinado> apadrinadoListOrphanCheck = proyecto.getApadrinadoList();
            for (Apadrinado apadrinadoListOrphanCheckApadrinado : apadrinadoListOrphanCheck) {
                if (illegalOrphanMessages == null) {
                    illegalOrphanMessages = new ArrayList<String>();
                }
                illegalOrphanMessages.add("This Proyecto (" + proyecto + ") cannot be destroyed since the Apadrinado " + apadrinadoListOrphanCheckApadrinado + " in its apadrinadoList field has a non-nullable proyecto field.");
            }
            List<PersonaContacto> personaContactoListOrphanCheck = proyecto.getPersonaContactoList();
            for (PersonaContacto personaContactoListOrphanCheckPersonaContacto : personaContactoListOrphanCheck) {
                if (illegalOrphanMessages == null) {
                    illegalOrphanMessages = new ArrayList<String>();
                }
                illegalOrphanMessages.add("This Proyecto (" + proyecto + ") cannot be destroyed since the PersonaContacto " + personaContactoListOrphanCheckPersonaContacto + " in its personaContactoList field has a non-nullable proyecto field.");
            }
            if (illegalOrphanMessages != null) {
                throw new IllegalOrphanException(illegalOrphanMessages);
            }
            List<Persona> personaList = proyecto.getPersonaList();
            for (Persona personaListPersona : personaList) {
                personaListPersona.getProyectoList().remove(proyecto);
                personaListPersona = em.merge(personaListPersona);
            }
            em.remove(proyecto);
            //Si et es falso significa que tengo que terminar la transaccion
            if (!et) {
                em.getTransaction().commit();
            }
        } finally {
            if (em != null) {
//                em.close();
            }
        }
    }

    /**
     * Método que busca una proyecto en la base de datos.
     * @param clase Class correspondiente al objeto a buscar
     * @param id Clave primaria del objeto a buscar
     * @return proyecto
     */
    @Override
    public Proyecto findEntidad(Class clase, Object id) {
        try {
            return (Proyecto) em.find(clase, id);
        } finally {
//            em.close();
        }
    }
}
